package com.bclz.state

case class State[S,+A](run:S=>(A,S)) {


  def flatMap[B](f:A=>State[S,B]):State[S,B]=State(
    s=>{
      val (a,_)=run(s)
      f(a).run(s)
    }
  )
  def map[B](f:A=>B):State[S,B]=this.flatMap(a=>State.unit(f(a)))

  def map2[B,C](sb:State[S,B])(f:(A,B)=>C):State[S,C]=
    this.flatMap(a=>sb.flatMap(b=>State.unit(f(a,b))))


}

object State{

  def unit[S,A](a:A):State[S,A]=
    State(s=>(a,s))

  def sequence[S,A](s1:List[State[S,A]]):State[S,List[A]]=s1 match {

    case Nil=>State(s=>(Nil,s))
    case h::t=>State(s=>(h.run(s)._1::sequence(t).run(s)._1,s))
  }
}